#pragma once
#include "conductivelayer.h"
#include "kernel/fePolyline.h"
#include "kernel/feLuSolver.h"
#include "kernel/feMatrix.h"
#include "kernel/feVector.h"

#define MAX_LAYERS 200
#define MAX_COLS 1000
#define MAX_ROWS 100
#define MAX_CURVES 100



class ReverseTask
{
public:
	typedef fePolyline<double> Curve;


private:
	feVector E0[MAX_CURVES];
	feVector E[MAX_CURVES];
	double   LastSSqr;

	Curve	DuDalpha1;
	Curve	DuDalpha2;
	double  OptStep;
	
	
	double **DerMatrixTransposed;
	int		DerMatrixCols;
	int		DerMatrixRows;
	
	feDenseMatrix SlaeMatrix;
	feDenseMatrix RegSlaeMatrix;
	double		  RightBuf[2*MAX_LAYERS-1];
	feVector	  SlaeRight;
	feVector	  SlaeX0;
	feVector	  SlaeX1;

	feLuSolver  Solver;
	double		RegCoeffSigma;
	double		RegCoeffH;
	bool		StepFound;

private:
	void FillDerivMatrix();
	void GetE0();
	void GetU(double iAlpha, feVector *oX);
	void FillU();
	void GetOptStep();
	bool PerformStep();
	double GetNorm(double iT);
	void FillE(Curve *iOrigCurve, Curve *iActCurve, feVector *oE);


protected:
	int				CurvesCount;
	Curve			AbnomalCurves[MAX_CURVES];
	Curve			ActualCurves[MAX_CURVES];
	Curve			OriginalCurves[MAX_CURVES];
	
	ConductiveLayer FirstMediumLog[MAX_LAYERS];
	ConductiveLayer OldMedium[MAX_LAYERS];
	ConductiveLayer Medium[MAX_LAYERS];
	ConductiveLayer OldMediumLog[MAX_LAYERS];
	ConductiveLayer MediumLog[MAX_LAYERS];
	int				LayersNum;
	
	
	virtual void CalcAbnormalCurve(int iIndex, ConductiveLayer *iNewMedium, int iLayersCount) = 0;
	virtual void CalcActualCurve(int iIndex) = 0;
	virtual void AfterInit() {}
	virtual void LogMedium(ConductiveLayer *iMedium, ConductiveLayer *oMedium, int iLayersCount);
	virtual void ExpMedium(ConductiveLayer *iMedium, ConductiveLayer *oMedium, int iLayersCount);
	
public:
	ReverseTask();
	void	BindData(ConductiveLayer *iLayers, int iLayersCount, Curve *iOrigCurves, int iCurvesNum, double iRegCoeffH=0, double iRegCoeffSigma=0);
	void	Iterate();
	double	GetEps();
	void	GetSolvation(ConductiveLayer *oLayers, int &oLayersNum);
	void	SplitMesh();

	virtual ~ReverseTask();
};
